package DataModel.DesignRulesManager;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.LinkedList;

import DataModel.CommonLibrary.CommonDefs.Layer;
import DataModel.DesignRulesManager.CCommonUtils.EDesignRuleType;

/**
 * Class for parsing design rules text file
 * 
 * @author evgeni
 *
 */
public class CDesignRulesParser 
{	
	/***************************************************/
	/****** C'tor **************************************/
	/***************************************************/
	public CDesignRulesParser(URL fileURL, LinkedList<CDesignRule> drList, Integer drcConst)
	{
		m_designRules = drList;
		m_drcConst = drcConst;
		
		readInputFile(fileURL);
	}
	
	/***************************************************/
	/****** Members **************************************/
	/***************************************************/
	private String m_filePath;  		// Name of the file being input.
	private InputStream m_inputStream;	// The raw input stream.
	private LineNumberReader m_lineReader;// The line number reader (text only)
	private LinkedList<CDesignRule> m_designRules;  // list of design rules
	private Integer m_drcConst;
	
	
	/***************************************************/
	/****** Public methods *****************************/
	/***************************************************/
	
	/**
	 * Parse the design rules file 
	 * @return false on success
	 */
	public boolean Parse()
	{
		String line = null;
		
		try 
		{				
			// first line should contain drc const
			try{
			m_drcConst = Integer.valueOf(m_lineReader.readLine());
			}
			catch (Exception e) {
				System.out.println("Error: First line in DRC file should contain drc const");				
				return true;
			}
			
			line = m_lineReader.readLine();
			
			while(line != null)
			{
				if(parseLine(line))
					return true;
				
				line = m_lineReader.readLine();
			}
		} 
		catch (IOException e) 
		{
			e.printStackTrace();
		}
		
		return false;
	}
	
	
	/***************************************************/
	/****** Utils **************************************/
	/***************************************************/
    private boolean readInputFile(URL fileURL)
	{
		m_filePath = fileURL.getFile();

        try
		{
			URLConnection urlCon = fileURL.openConnection();
            urlCon.setConnectTimeout(10000);
            urlCon.setReadTimeout(1000);

			m_inputStream = urlCon.getInputStream();
		} 
        catch (IOException e)
		{
			System.out.println("Could not find file: " + m_filePath);
			return true;
		}
		
        InputStreamReader is = new InputStreamReader(m_inputStream);
        m_lineReader = new LineNumberReader(is);
        
        return false;
	}	
    
    private boolean parseLine(String line)
    {
    	if(line == null)
    		return true;

    	String id = readWord(line);
    	String type = readWord(line.substring(id.length()));
    	String firstLayer = readWord(line.substring((id+type).length()+1));
    	String secondLayer = readWord(line.substring((id+type+firstLayer).length()+2));
    	String value = readWord(line.substring((id+type+firstLayer+secondLayer).length()+3));

    	CDesignRule designRule = new CDesignRule();
    	
    	designRule.setId(id);
    	designRule.setType(getType(type));
    	designRule.setFirstLayer(getLayer(firstLayer));
    	designRule.setSecondLayer(getLayer(secondLayer));
    	designRule.setValue(getNumber(value)*m_drcConst);
    	
    	m_designRules.add(designRule);
    	
    	return false;
    }
    
    private double getNumber(String number)
    {
    	return Double.valueOf(number);
    }
    
    private EDesignRuleType getType(String type)
    {
    	if(type.equals("WIDTH"))
    		return EDesignRuleType.WIDTH;
    	
    	if(type.equals("SPACING"))
    		return EDesignRuleType.SPACING;
    	
    	if(type.equals("EXTENSION"))
    		return EDesignRuleType.EXTENSION;
    	
    	if(type.equals("OVERLAP"))
    		return EDesignRuleType.OVERLAP;
    	
    	if(type.equals("EXACT"))
    		return EDesignRuleType.EXACT;
    			
    	return EDesignRuleType.UNKNOWN;
    }
    
    private Layer getLayer(String layer)
    {
    	if(layer.equals("ACTIVE"))
    		return Layer.Active;
    	
    	if(layer.equals("NWELL"))
    		return Layer.Nwel;
    	
    	if(layer.equals("PWELL"))
    		return Layer.Pwel;
    	
    	if(layer.equals("NDIFF"))
			return Layer.N_diff;
		
		if(layer.equals("PDIFF"))
			return Layer.P_diff;
		
		if(layer.equals("POLY"))
			return Layer.Poly;
		
		if(layer.equals("CONTACT"))
			return Layer.Contact;
		
		if(layer.equals("M1"))
			return Layer.Metal1;
		
		if(layer.equals("M2"))
			return Layer.Metal2;
		
		if(layer.equals("M3"))
			return Layer.Metal3;
		
		if(layer.equals("M4"))
			return Layer.Metal4;
		
		if(layer.equals("M5"))
			return Layer.Metal5;
		
		if(layer.equals("VIA12"))
			return Layer.Via1_2;
		
		if(layer.equals("VIA23"))
			return Layer.Via2_3;
		
		if(layer.equals("VIA34"))
			return Layer.Via3_4;
		
		if(layer.equals("VIA45"))
			return Layer.Via4_5;

    	return Layer.None;
    }
    
    private String readWord(String line)
    {
    	StringBuffer word = new StringBuffer();
    	int index = 0;
    	
    	// skip spaces
    	for(; index<line.length(); index++)
    		if(line.charAt(index) != ' ')
    			break;
    	
    	// read word
    	for(;index<line.length();index++)
    	{
    		char ch = line.charAt(index);
    		
    		if(ch != ' ')
    			word.append(ch);
    		else
    			break;
    	}
    	
    	return word.toString();
    }
}
